// 视图更新后的操作
function cb(val) {
  console.log('视图更新了', val)
}
// 对对象的某个属性设置 setter 与 getter 函数
// obj:需要绑定的对象
// key:obj的某一个属性
// val：具体值
function defineReactive(obj, key, val) {
  /* 一个Dep类对象 */
  const dep = new Dep()
  Object.defineProperty(obj, key, {
    enumerable: true /* 属性可枚举 */,
    configurable: true /* 属性可被修改或删除 */,
    get: function reactiveGetter() {
      /* 将Dep.target（即当前的Watcher对象存入dep的subs中） */
      console.log('get执行了')
      dep.addSub(Dep.target)
      return val
    },
    set: function reactiveSetter(newVal) {
      if (newVal === val) return
      /* 在set的时候触发dep的notify来通知所有的Watcher对象更新视图 */
      console.log('set执行了')
      dep.notify()
      // val = newVal;
      // cb(newVal);
    }
  })
}
// 遍历对象的每个属性,设置setter getter方法
// value:需要响应化的对象
function observer(value) {
  if (!value || typeof value !== 'object') {
    return
  }

  Object.keys(value).forEach(key => {
    defineReactive(value, key, value[key])
  })
}

class Dep {
  constructor() {
    /* 用来存放Watcher对象的数组 */
    this.subs = []
  }

  /* 在subs中添加一个Watcher对象 */
  addSub(sub) {
    this.subs.push(sub)
  }

  /* 通知所有Watcher对象更新视图 */
  notify() {
    this.subs.forEach(sub => {
      sub.update()
    })
  }
}
class Watcher {
  constructor() {
    /* 在new一个Watcher对象时将该对象赋值给Dep.target，在get中会用到 */
    Dep.target = this
  }

  /* 更新视图的方法 */
  update() {
    console.log('视图更新啦～')
  }
}

// 对vuedata 中的data进行setter和getter
class Vue {
  /* Vue构造类 */
  constructor(options) {
    this._data = options.data
    observer(this._data)
    /* 新建一个Watcher观察者对象，这时候Dep.target会指向这个Watcher对象 */
    new Watcher()
    /* 在这里模拟render的过程，为了触发test属性的get函数 */
    console.log('render~', this._data.test)
  }
}
let o = new Vue({
  data: {
    test: 'I am test.'
  }
})
o._data.test = 'hello,world' /* 视图更新啦～ */
